/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.huawei.housekeeper.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huawei.housekeeper.constant.ServieStatusEnum;
import com.huawei.housekeeper.constants.DeletedFlagEnum;
import com.huawei.housekeeper.controller.converter.HousekeeperServiceConverter;
import com.huawei.housekeeper.controller.request.*;
import com.huawei.housekeeper.controller.response.HouseKeeperServiceListVo;
import com.huawei.housekeeper.controller.response.HouseKeeperServiceVo;
import com.huawei.housekeeper.controller.response.ServiceInfoRespVo;
import com.huawei.housekeeper.dao.entity.*;
import com.huawei.housekeeper.dao.mapper.*;
import com.huawei.housekeeper.enums.ErrorCode;
import com.huawei.housekeeper.exception.Assert;
import com.huawei.housekeeper.result.ListRes;
import com.huawei.housekeeper.service.IHouseKeeperService;
import com.huawei.housekeeper.utils.CopyUtils;
import com.huawei.housekeeper.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 功能描述 服务功能类
 *
 * @author jWX1116205
 * @since 2022-01-17
 */
@Slf4j
@Service
public class HouseKeeperServiceImpl implements IHouseKeeperService {
    @Autowired
    private HousekeeperServiceMapper housekeeperServiceMapper;

    @Autowired
    private ServiceOptionMapper serviceOptionMapper;

    @Autowired
    private ServiceSelectionMapper serviceSelectionMapper;

    @Autowired
    private ServiceSkuMapper serviceSkuMapper;

    @Autowired
    private ServiceSpecificationMapper serviceSpecificationMapper;

    @Autowired
    private TokenUtil tokenUtil;
    @Autowired
    private ServiceImageMapper serviceImageMapper;
    @Override
    public ServiceInfoRespVo getHousekeeperServiceVoById(GetServiceDto getServiceListReq) {
        Long serviceId = getServiceListReq.getServiceId();
        HousekeeperService housekeeperService = housekeeperServiceMapper.selectById(serviceId);
        Assert.notNull(housekeeperService, ErrorCode.SERVICE_SELECT_EMPTY.getCode(),
            ErrorCode.SERVICE_SELECT_EMPTY.getMessage());
        ServiceInfoRespVo serviceInfoResp = buildServiceInfoRespVo(housekeeperService);

        // 构建服务规格返回主体，与Sku拥有的属性无关
        LambdaQueryWrapper<ServiceSpecification> selecSpecQuery = Wrappers.lambdaQuery();
        selecSpecQuery.eq(ServiceSpecification::getServiceId, serviceId);
        selecSpecQuery.eq(ServiceSpecification::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        List<ServiceSpecification> serviceSpecificationList = serviceSpecificationMapper.selectList(selecSpecQuery);

        // 如果规格为空则说明服务未配置可选服务
        if (CollectionUtils.isEmpty(serviceSpecificationList)) {
            return serviceInfoResp;
        }

        // 建服务规格返回主体，与Sku拥有的属性无关
        serviceInfoResp.setSpecs(buildServiceSpecs(serviceSpecificationList));

        // 构建服务Sku
        serviceInfoResp.setSkus(buildSkuList(serviceId, serviceSpecificationList));
        return serviceInfoResp;
    }

    /**
     * 构建服务Sku
     *
     * @param serviceId                服务id
     * @param serviceSpecificationList 列表
     * @return {@link List<ServiceInfoRespVo.SkusItem>}
     */
    private List<ServiceInfoRespVo.SkusItem> buildSkuList(Long serviceId,
        List<ServiceSpecification> serviceSpecificationList) {
        List<ServiceInfoRespVo.SkusItem> skus = new ArrayList<>();
        LambdaQueryWrapper<ServiceSku> selectSkuQuery = Wrappers.lambdaQuery();
        selectSkuQuery.eq(ServiceSku::getServiceId, serviceId);
        selectSkuQuery.eq(ServiceSku::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        List<ServiceSku> serviceSkuList = serviceSkuMapper.selectList(selectSkuQuery);
        if (CollectionUtils.isEmpty(serviceSkuList)) {
            return skus;
        }
        List<Long> skuIds = serviceSkuList.stream().map(ServiceSku::getId).collect(Collectors.toList());

        // 通过Sku下的规格查询服务选集
        LambdaQueryWrapper<ServiceSelection> selecSelectionQuery = Wrappers.lambdaQuery();
        selecSelectionQuery.in(ServiceSelection::getSkuId, skuIds);
        List<ServiceSelection> selectListOfServiceId = serviceSelectionMapper.selectList(selecSelectionQuery);
        Map<Long, List<ServiceSelection>> selectionMapGroupBySkuId = selectListOfServiceId.stream()
            .collect(Collectors.groupingBy(ServiceSelection::getSkuId, Collectors.toList()));
        List<Long> optionIds = selectListOfServiceId.stream()
            .map(ServiceSelection::getOptionId)
            .collect(Collectors.toList());

        // 通过服务选集查询规格选项
        List<ServiceOption> optionListOfOptionIds = serviceOptionMapper.selectBatchIds(optionIds);
        Map<Long, ServiceOption> optionIdMap = optionListOfOptionIds.stream()
            .collect(Collectors.toMap(ServiceOption::getId, Function.identity(), (k1, k2) -> k2));
        Map<Long, ServiceSpecification> specIdMap = serviceSpecificationList.stream()
            .collect(Collectors.toMap(ServiceSpecification::getId, Function.identity(), (k1, k2) -> k2));
        serviceSkuList.forEach(sku -> {
            ServiceInfoRespVo.SkusItem skusItem = new ServiceInfoRespVo.SkusItem();
            skusItem.setSkuId(sku.getId());
            skusItem.setPrice(sku.getPrice());
            if (!CollectionUtils.isEmpty(selectionMapGroupBySkuId) && selectionMapGroupBySkuId.keySet()
                .contains(sku.getId())) {
                // 可选服务
                List<ServiceInfoRespVo.OptionProperty> selections = selectionMapGroupBySkuId.get(sku.getId())
                    .stream()
                    .map(selection -> {
                        ServiceInfoRespVo.OptionProperty property = new ServiceInfoRespVo.OptionProperty();
                        property.setSelectionId(selection.getId());
                        property.setOptionId(selection.getOptionId());
                        ServiceOption option = optionIdMap.get(selection.getOptionId());
                        property.setOptionName(option.getName());
                        property.setSpecName(specIdMap.get(option.getSpecificationId()).getName());
                        return property;
                    })
                    .collect(Collectors.toList());
                skusItem.setSelections(selections);
            }
            skus.add(skusItem);
        });
        return skus;
    }

    /**
     * 建服务规格返回主体，与Sku拥有的属性无关
     *
     * @param serviceSpecificationList 列表
     * @return {@link List<ServiceInfoRespVo.SpecsItem>}
     */
    private List<ServiceInfoRespVo.SpecsItem> buildServiceSpecs(List<ServiceSpecification> serviceSpecificationList) {
        List<ServiceInfoRespVo.SpecsItem> specs = new ArrayList<>();
        if (CollectionUtils.isEmpty(serviceSpecificationList)) {
            return specs;
        }

        // 查询规格下的规格选项
        List<Long> specIds = serviceSpecificationList.stream()
            .map(ServiceSpecification::getId)
            .collect(Collectors.toList());
        LambdaQueryWrapper<ServiceOption> selectOptioncQuery = Wrappers.lambdaQuery();
        selectOptioncQuery.in(ServiceOption::getSpecificationId, specIds);
        List<ServiceOption> optionListOfServiceId = serviceOptionMapper.selectList(selectOptioncQuery);
        Map<Long, List<ServiceOption>> optionListGroupBySpecId = optionListOfServiceId.stream()
            .collect(Collectors.groupingBy(ServiceOption::getSpecificationId, LinkedHashMap::new, Collectors.toList()));
        serviceSpecificationList.forEach(spec -> {
            ServiceInfoRespVo.SpecsItem specsItem = new ServiceInfoRespVo.SpecsItem();
            specsItem.setSpecId(spec.getId());
            specsItem.setName(spec.getName());

            // 规格下的规格选项
            List<ServiceOption> optionItemList = optionListGroupBySpecId.get(spec.getId());
            List<ServiceInfoRespVo.OptionProperty> options = optionItemList.stream().map(opt -> {
                ServiceInfoRespVo.OptionProperty property = new ServiceInfoRespVo.OptionProperty();
                property.setOptionId(opt.getId());
                property.setOptionName(opt.getName());
                property.setSpecName(spec.getName());
                return property;
            }).collect(Collectors.toList());
            specsItem.setOptions(options);
            specs.add(specsItem);
        });
        return specs;
    }

    /**
     * 初始化 查询单个服务响应vo
     *
     * @param housekeeperService 查询参数
     * @return {@link com.huawei.housekeeper.controller.response.ServiceInfoRespVo}
     */
    private ServiceInfoRespVo buildServiceInfoRespVo(HousekeeperService housekeeperService) {
        ServiceInfoRespVo serviceInfoResp = new ServiceInfoRespVo();
        serviceInfoResp.setServiceName(housekeeperService.getServiceName());
        serviceInfoResp.setServiceDesc(housekeeperService.getServiceDesc());
        serviceInfoResp.setImgSrc(housekeeperService.getImgSrc());
        serviceInfoResp.setDisplayPrice(housekeeperService.getDisplayPrice());
        serviceInfoResp.setServcieId(housekeeperService.getId());
        return serviceInfoResp;
    }

    /**
     * 分页查询服务列表
     *
     * @param getServiceListReq 查询参数
     * @return {@link ListRes<HouseKeeperServiceListVo>}
     */
    @Override
    public ListRes<HouseKeeperServiceListVo> getHousekeeperServicePageByParam(GetServiceListDto getServiceListReq) {
        Map<String, Object> criteria = CopyUtils.copyToMap(getServiceListReq);
        int count = housekeeperServiceMapper.getHouseKeeperServiceCountByParam(criteria);
        List<HouseKeeperServiceListVo> resultList = new ArrayList<>();
        if (count > NumberUtils.INTEGER_ZERO) {
            resultList = housekeeperServiceMapper.getHouseKeeperServicePageByParam(criteria);
        }
        return new ListRes<>(resultList, count);
    }

    /**
     * 服务预定首页查询
     *
     * @param getServiceListReq 查询参数
     * @return {@link ListRes<HouseKeeperServiceListVo>}
     */
    @Override
    public ListRes<HouseKeeperServiceListVo> getHousekeeperServiceIndexPageByParam(
        GetServiceListDto getServiceListReq) {
        Map<String, Object> criteria = CopyUtils.copyToMap(getServiceListReq);
        int count = housekeeperServiceMapper.getHouseKeeperServiceCountIndexByParam(criteria);
        List<HouseKeeperServiceListVo> resultList = new ArrayList<>();
        if (count > NumberUtils.INTEGER_ZERO) {
            List<HousekeeperService> serviceList = housekeeperServiceMapper.getHouseKeeperServiceIndexPageByParam(
                criteria);
            resultList = CopyUtils.copyList(serviceList, HouseKeeperServiceListVo.class);
        }
        return new ListRes<>(resultList, count);
    }

    /**
     * 根据服务id查询服务基本信息
     *
     * @param getServiceDto 服务数据
     * @return {@link HouseKeeperServiceVo}
     */
    @Override
    public HouseKeeperServiceVo queryHousekeeperServiceVoById(GetServiceDto getServiceDto) {
        HousekeeperService houseKeeperService = housekeeperServiceMapper.selectById(getServiceDto.getServiceId());
        HouseKeeperServiceVo houseKeeperServiceVo = new HouseKeeperServiceVo();
        CopyUtils.copyProperties(houseKeeperService, houseKeeperServiceVo);
        houseKeeperServiceVo.setServiceId(houseKeeperService.getId());
        return houseKeeperServiceVo;
    }

    /**
     * 创建服务
     *
     * @param createServiceDto 服务数据
     * @return {@link int}
     */
    @Override
    public Long createHousekeeperService(CreateServiceDto createServiceDto) {
        HousekeeperService serviceObj = HousekeeperServiceConverter.INSTANCE.createHousekeeperServiceByDto(
            createServiceDto);
        serviceObj.setDeleteFlag(DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        serviceObj.setServieStatus(ServieStatusEnum.SERVICE_APPLAY.getCode());
        checkServiceNameRepeat(serviceObj.getServiceName());
        housekeeperServiceMapper.insert(serviceObj);
        LambdaUpdateWrapper<ServiceImage> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(ServiceImage::getImgSrc,createServiceDto.getImgSrc());
        updateWrapper.eq(ServiceImage::getServiceId,serviceObj.getId());
        serviceImageMapper.update(new ServiceImage(),updateWrapper);
        return serviceObj.getId();
    }

    /**
     * 更新服务
     *
     * @param updateServiceDto 服务数据
     * @return {@link int}
     */
    @Override
    public Long updateHousekeeperService(UpdateServiceDto updateServiceDto) {
        HousekeeperService updateObj = HousekeeperServiceConverter.INSTANCE.createHousekeeperServiceByDto(
            updateServiceDto);
        CopyUtils.copyProperties(updateServiceDto, updateObj);
        updateObj.setId(updateServiceDto.getServiceId());
        housekeeperServiceMapper.updateById(updateObj);
        return updateObj.getId();
    }

    /**
     * 删除服务
     *
     * @param deleteServiceDto 服务数据
     * @return {@link int}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long deleteHousekeeperService(DeleteServiceDto deleteServiceDto) {
        // 1.删除服务
        HousekeeperService dbEntity = housekeeperServiceMapper.selectById(deleteServiceDto.getServiceId());
        Assert.notNull(dbEntity, ErrorCode.SERVICE_NOT_EXIST.getCode(), ErrorCode.SERVICE_NOT_EXIST.getMessage());
        dbEntity.setDeleteFlag(DeletedFlagEnum.SERVICE_FLAGE_DELETED.getCode());
        housekeeperServiceMapper.updateById(dbEntity);
        LambdaQueryWrapper<ServiceSpecification> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ServiceSpecification::getServiceId, deleteServiceDto.getServiceId());
        List<ServiceSpecification> serviceSpecificationList = serviceSpecificationMapper.selectList(queryWrapper);
        String updatedBy = tokenUtil.getUserNameFromHeader();

        // 2.删除服务规格
        if (!CollectionUtils.isEmpty(serviceSpecificationList)) {
            List<Long> specIds = serviceSpecificationList.stream()
                .collect(Collectors.mapping(ServiceSpecification::getId, Collectors.toList()));
            serviceSpecificationMapper.deleteSpecificationByIds(specIds, updatedBy);

            // 3.删除服务规格选项
            serviceOptionMapper.deleteBySpecificationIds(specIds, updatedBy);
        }
        LambdaQueryWrapper<ServiceSku> queryWrapperForServiceSku = Wrappers.lambdaQuery();
        queryWrapperForServiceSku.eq(ServiceSku::getServiceId, deleteServiceDto.getServiceId());

        // 4.删除服务SKU
        List<ServiceSku> serviceSkus = serviceSkuMapper.selectList(queryWrapperForServiceSku);
        if (!CollectionUtils.isEmpty(serviceSkus)) {
            serviceSkuMapper.deleteByServcieId(deleteServiceDto.getServiceId(), updatedBy);
            List<Long> skuIds = serviceSkus.stream()
                .collect(Collectors.mapping(ServiceSku::getId, Collectors.toList()));

            // 5.删除服务选集
            serviceSelectionMapper.deleteBySkuIds(skuIds, updatedBy);
        }
        return deleteServiceDto.getServiceId();
    }

    /**
     * 验证服务名是否重复
     *
     * @param serviceName 服务名
     */
    private void checkServiceNameRepeat(String serviceName) {
        LambdaQueryWrapper<HousekeeperService> selectQuery = Wrappers.lambdaQuery();
        selectQuery.eq(HousekeeperService::getServiceName, serviceName);
        List<HousekeeperService> serviceNameList = housekeeperServiceMapper.selectList(selectQuery);
        Assert.isTrue(CollectionUtils.isEmpty(serviceNameList), ErrorCode.SERVICE_NAME_REPEATED.getCode(),
            ErrorCode.SERVICE_NAME_REPEATED.getMessage());
    }

}